/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

import React, { CSSProperties, useEffect, useRef, useState } from 'react';
import { RenderFunc } from 'rc-virtual-list/lib/interface';
import { Divider, List, Space, Spin } from 'antd';
import { PullToRefresh, InfiniteScroll } from 'antd-mobile';
import styles from './index.less';
import classNames from 'classnames';
import { isFunction, isPlainObject } from 'lodash';
import { CheckOutlined, LoadingOutlined } from '@ant-design/icons';

export type ListExtendRequestStatus = 'init' | 'refresh' | 'more';

export interface ListExtendRequestParams {
  current: number;
  pageSize: number;
  status: ListExtendRequestStatus;
  [Props: string]: any;
}

export interface ListExtendRefCurrent {
  current?: number;
  list?: any[];
  payload?: any;
  intercept?: boolean;
  update: (list: any[]) => void;
  reload?: (p?: any) => Promise<any>;
}

interface ListExtendProps<T> extends Omit<React.HTMLAttributes<any>, 'children'> {
  children: RenderFunc<T>;
  active?: any;
  pageSize?: number;
  emptyText?: string | React.ReactNode;
  className?: string;
  listClassName?: string;
  pullDownToRefresh?: boolean;
  pullUpToMore?: boolean;
  request: (p: ListExtendRequestParams) => Promise<{ list: T[] | null }>;
  header?: React.ReactNode;
  footer?: React.ReactNode;
  onReady?: (cur: ListExtendRefCurrent) => void;
  onUpdate?: (list: T[]) => void;
  style?: CSSProperties;
}

const ListExtend = <T extends Record<string, any>>(props: ListExtendProps<T>) => {
  const {
    request,
    active = true,
    pageSize = 30,
    pullDownToRefresh = true,
    pullUpToMore = true,
    emptyText,
    className,
    listClassName,
    header,
    footer,
    onReady,
    onUpdate,
    style,
  } = props;
  const [list, setList] = useState<T[]>([]);
  const [loading, setLoading] = useState(false);
  const [loadingMore, setLoadingMore] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const listExtendRef = useRef<ListExtendRefCurrent>({
    current: 1,
    update: (l) => setList(l),
    list: [],
    reload: () => Promise.resolve(),
    payload: null,
    intercept: false,
  });

  const listLen = list.length;
  const hasList = listLen > 0;

  const rootCls = classNames(styles.listWrapper, className);
  const listCls = classNames(styles.list, listClassName, {
    [styles.listNoData]: !hasList,
  });

  // 检查是否有更多
  const checkHasMore = (l: T[] | null) => !!(l && l.length >= pageSize);

  // 触发请求
  const triggerRequest = async (p: any) => {
    const { payload: prePayload } = listExtendRef.current;
    const payload = { pageSize, ...prePayload, ...p };
    listExtendRef.current.payload = payload;
    return await request(payload);
  };

  // 刷新数据
  const refresh = async (p?: any, status = 'refresh') => {
    if (listExtendRef.current.intercept) return;
    listExtendRef.current.current = 1;
    setLoading(true);
    return await triggerRequest({ ...p, current: 1, status })
      .then(({ list: cur }) => {
        setHasMore(checkHasMore(cur));
        setList(cur || []);
      })
      .finally(() => setLoading(false));
  };

  // 加载更多
  const more = async () => {
    if (listExtendRef.current.intercept || !hasMore) return;
    listExtendRef.current.current!++;
    setLoadingMore(true);
    return await triggerRequest({ current: listExtendRef.current.current, status: 'more' })
      .then(({ list: cur }) => {
        setHasMore(checkHasMore(cur));
        setList((pre) => pre.concat(cur || []));
      })
      .finally(() => setLoadingMore(false));
  };

  // 初始化
  useEffect(() => {
    listExtendRef.current.reload = async (p) => {
      listExtendRef.current.payload = p;
      return await refresh(p, 'init');
    };
    if (isFunction(onReady)) {
      onReady(listExtendRef.current);
    }
  }, []);

  // 记录限制
  useEffect(() => {
    listExtendRef.current.intercept = !active || loading;
  }, [active, loading]);

  // 初始化
  useEffect(() => {
    const p = isPlainObject(active) ? active : null;
    listExtendRef.current.reload!(p);
  }, [active]);

  // list更新
  useEffect(() => {
    listExtendRef.current.list = list;
    if (isFunction(onUpdate)) {
      onUpdate(list);
    }
  }, [list]);

  return (
    <div className={rootCls} style={style}>
      <PullToRefresh
        disabled={!pullDownToRefresh}
        onRefresh={refresh}
        pullingText='&#8595; 继续下拉'
        canReleaseText='&#8593; 释放刷新'
        completeText={
          <Space>
            <CheckOutlined style={{ fontSize: 12 }} />
            <span>已更新</span>
          </Space>
        }
        refreshingText={<LoadingOutlined />}
      >
        <List
          className={listCls}
          loading={loading}
          dataSource={list}
          locale={{ emptyText }}
          renderItem={(item, index) => props.children(item, index, {})}
          header={header}
          footer={footer}
        />
        {pullUpToMore && hasList ? (
          <InfiniteScroll loadMore={more} hasMore={hasMore}>
            <>
              {!hasMore ? (
                <Divider className={styles.listDivider}>没有更多了</Divider>
              ) : loadingMore ? (
                <div className={styles.listLoader}>
                  <Spin size='small' spinning />
                </div>
              ) : null}
            </>
          </InfiniteScroll>
        ) : null}
      </PullToRefresh>
    </div>
  );
};

export default ListExtend;
